#include "tts_interface.h"
#include <iostream>
#include <cstring>
#include <unistd.h>

using namespace std;
using namespace AIKIT;

std::atomic_bool TTSInterface::m_ttsFinished(false);
TTSInterface* TTSInterface::m_instance = nullptr;

TTSInterface::TTSInterface(const std::string& role) 
    : m_role(role), m_handle(nullptr), m_initialized(false) {
    m_instance = this;
}

TTSInterface::~TTSInterface() {
    cleanup();
    m_instance = nullptr;
}

bool TTSInterface::initialize() {
    if (m_initialized) {
        return true;
    }

    AIKIT_Configurator::builder()
        .app()
            .appID("bcf15145")
            .apiSecret("NGMzYmI5MTE0MGYzYjk1ODRlMWRhNDA1")
            .apiKey("3a0e16e1a988d976d094b3835dd899e3")
            .workDir("./")
            .resDir("/oem/aikit/resource/")
            .cfgFile("")
        .auth()
            .authType(0)
        .log()
            .logLevel(LOG_LVL_VERBOSE)
            .logMode(LOG_FILE)
            .logPath("../log/xtts_aikit.log");

    int ret = AIKIT_Init();
    if (ret != 0) {
        if (m_errorCallback) {
            m_errorCallback("AIKIT_Init failed: " + to_string(ret));
        }
        return false;
    }

    AIKIT_Callbacks cbs = {OnOutput, OnEvent, OnError};
    AIKIT_RegisterAbilityCallback("e2e44feff", cbs);
    
    m_initialized = true;
    return true;
}

bool TTSInterface::speak(const std::string& text) {
    if (!m_initialized) {
        if (!initialize()) {
            return false;
        }
    }

    AIKIT_ParamBuilder* paramBuilder = nullptr;
    AIKIT_DataBuilder* dataBuilder = nullptr;
    AiText* aiText_raw = nullptr;
    m_ttsFinished = false;

    paramBuilder = AIKIT_ParamBuilder::create();
    paramBuilder->clear();
    paramBuilder->param("vcn", m_role.c_str(), m_role.length());
    paramBuilder->param("vcnModel", m_role.c_str(), m_role.length());
    paramBuilder->param("language", 1);
    paramBuilder->param("textEncoding", "UTF-8", strlen("UTF-8"));

    int ret = AIKIT_Start("e2e44feff", AIKIT_Builder::build(paramBuilder), nullptr, &m_handle);
    if (ret != 0) {
        if (m_errorCallback) {
            m_errorCallback("AIKIT_Start failed: " + to_string(ret));
        }
        goto cleanup;
    }

    dataBuilder = AIKIT_DataBuilder::create();
    dataBuilder->clear();
    aiText_raw = AiText::get("text")->data(text.c_str(), text.length())->once()->valid();
    dataBuilder->payload(aiText_raw);

    ret = AIKIT_Write(m_handle, AIKIT_Builder::build(dataBuilder));
    if (ret != 0) {
        if (m_errorCallback) {
            m_errorCallback("AIKIT_Write failed: " + to_string(ret));
        }
        goto cleanup;
    }

cleanup:
    if (paramBuilder != nullptr) {
        delete paramBuilder;
    }
    if (dataBuilder != nullptr) {
        delete dataBuilder;
    }

    return (ret == 0);
}

void TTSInterface::setAudioCallback(AudioCallback callback) {
    m_audioCallback = callback;
}

void TTSInterface::setErrorCallback(ErrorCallback callback) {
    m_errorCallback = callback;
}

void TTSInterface::setCompletionCallback(CompletionCallback callback) {
    m_completionCallback = callback;
}

void TTSInterface::waitForCompletion() {
    while (!m_ttsFinished) {
        usleep(1000);
    }
}

void TTSInterface::cleanup() {
    if (m_handle) {
        AIKIT_End(m_handle);
        m_handle = nullptr;
    }
    
    if (m_initialized) {
        AIKIT_UnInit();
        m_initialized = false;
    }
}

void TTSInterface::OnOutput(AIKIT_HANDLE* handle, const AIKIT_OutputData* output) {
    if (m_instance && m_instance->m_audioCallback && output->node->value && output->node->len > 0) {
        m_instance->m_audioCallback((const char*)output->node->value, output->node->len);
    }
}

void TTSInterface::OnEvent(AIKIT_HANDLE* handle, AIKIT_EVENT eventType, const AIKIT_OutputEvent* eventValue) {
    if (eventType == AIKIT_Event_End) {
        m_ttsFinished = true;
        if (m_instance && m_instance->m_completionCallback) {
            m_instance->m_completionCallback();
        }
    }
}

void TTSInterface::OnError(AIKIT_HANDLE* handle, int32_t err, const char* desc) {
    m_ttsFinished = true;
    if (m_instance && m_instance->m_errorCallback) {
        string errorMsg = "TTS Error: " + to_string(err) + " - " + string(desc);
        m_instance->m_errorCallback(errorMsg);
    }
}